﻿namespace S7.Net.Types
{
    using S7.Net;
    using System;
    using System.Reflection;

    public static class Struct
    {
        public static object FromBytes(Type structType, byte[] bytes)
        {
            if (bytes == null)
            {
                return null;
            }
            if (bytes.Length != GetStructSize(structType))
            {
                return null;
            }
            int index = 0;
            int num2 = 0;
            double d = 0.0;
            object obj2 = Activator.CreateInstance(structType);
            FieldInfo[] fields = obj2.GetType().GetFields();
            foreach (FieldInfo info in fields)
            {
                byte[] buffer;
                switch (info.FieldType.Name)
                {
                    case "Boolean":
                        index = (int) Math.Floor(d);
                        num2 = (int) ((d - index) / 0.125);
                        if ((bytes[index] & ((int) Math.Pow(2.0, (double) num2))) == 0)
                        {
                            break;
                        }
                        info.SetValue(obj2, true);
                        goto Label_0178;

                    case "Byte":
                    {
                        d = Math.Ceiling(d);
                        info.SetValue(obj2, bytes[(int) d]);
                        d++;
                        continue;
                    }
                    case "Int16":
                    {
                        d = Math.Ceiling(d);
                        if (((d / 2.0) - Math.Floor((double) (d / 2.0))) > 0.0)
                        {
                            d++;
                        }
                        ushort input = Word.FromBytes(bytes[((int) d) + 1], bytes[(int) d]);
                        info.SetValue(obj2, input.ConvertToShort());
                        d += 2.0;
                        continue;
                    }
                    case "UInt16":
                    {
                        d = Math.Ceiling(d);
                        if (((d / 2.0) - Math.Floor((double) (d / 2.0))) > 0.0)
                        {
                            d++;
                        }
                        info.SetValue(obj2, Word.FromBytes(bytes[((int) d) + 1], bytes[(int) d]));
                        d += 2.0;
                        continue;
                    }
                    case "Int32":
                    {
                        d = Math.Ceiling(d);
                        if (((d / 2.0) - Math.Floor((double) (d / 2.0))) > 0.0)
                        {
                            d++;
                        }
                        uint num5 = DWord.FromBytes(bytes[((int) d) + 3], bytes[((int) d) + 2], bytes[((int) d) + 1], bytes[(int) d]);
                        info.SetValue(obj2, num5.ConvertToInt());
                        d += 4.0;
                        continue;
                    }
                    case "UInt32":
                    {
                        d = Math.Ceiling(d);
                        if (((d / 2.0) - Math.Floor((double) (d / 2.0))) > 0.0)
                        {
                            d++;
                        }
                        info.SetValue(obj2, DWord.FromBytes(bytes[(int) d], bytes[((int) d) + 1], bytes[((int) d) + 2], bytes[((int) d) + 3]));
                        d += 4.0;
                        continue;
                    }
                    case "Double":
                    {
                        d = Math.Ceiling(d);
                        if (((d / 2.0) - Math.Floor((double) (d / 2.0))) > 0.0)
                        {
                            d++;
                        }
                        info.SetValue(obj2, S7.Net.Types.Double.FromByteArray(new byte[] { bytes[(int) d], bytes[((int) d) + 1], bytes[((int) d) + 2], bytes[((int) d) + 3] }));
                        d += 4.0;
                        continue;
                    }
                    default:
                        goto Label_0435;
                }
                info.SetValue(obj2, false);
            Label_0178:
                d += 0.125;
                continue;
            Label_0435:
                buffer = new byte[GetStructSize(info.FieldType)];
                if (buffer.Length != 0)
                {
                    Buffer.BlockCopy(bytes, (int) Math.Ceiling(d), buffer, 0, buffer.Length);
                    info.SetValue(obj2, FromBytes(info.FieldType, buffer));
                    d += buffer.Length;
                }
            }
            return obj2;
        }

        public static int GetStructSize(Type structType)
        {
            double a = 0.0;
            FieldInfo[] fields = structType.GetFields();
            foreach (FieldInfo info in fields)
            {
                switch (info.FieldType.Name)
                {
                    case "Boolean":
                        a += 0.125;
                        break;

                    case "Byte":
                        a = Math.Ceiling(a) + 1.0;
                        break;

                    case "Int16":
                    case "UInt16":
                        a = Math.Ceiling(a);
                        if (((a / 2.0) - Math.Floor((double) (a / 2.0))) > 0.0)
                        {
                            a++;
                        }
                        a += 2.0;
                        break;

                    case "Int32":
                    case "UInt32":
                        a = Math.Ceiling(a);
                        if (((a / 2.0) - Math.Floor((double) (a / 2.0))) > 0.0)
                        {
                            a++;
                        }
                        a += 4.0;
                        break;

                    case "Float":
                    case "Double":
                        a = Math.Ceiling(a);
                        if (((a / 2.0) - Math.Floor((double) (a / 2.0))) > 0.0)
                        {
                            a++;
                        }
                        a += 4.0;
                        break;

                    default:
                        a += GetStructSize(info.FieldType);
                        break;
                }
            }
            return (int) a;
        }

        public static byte[] ToBytes(object structValue)
        {
            Type structType = structValue.GetType();
            byte[] buffer = new byte[GetStructSize(structType)];
            byte[] buffer2 = null;
            int index = 0;
            int num3 = 0;
            double d = 0.0;
            FieldInfo[] fields = structType.GetFields();
            foreach (FieldInfo info in fields)
            {
                buffer2 = null;
                switch (info.FieldType.Name)
                {
                    case "Boolean":
                        index = (int) Math.Floor(d);
                        num3 = (int) ((d - index) / 0.125);
                        if (!((bool) info.GetValue(structValue)))
                        {
                            break;
                        }
                        buffer[index] = (byte) (buffer[index] | ((byte) Math.Pow(2.0, (double) num3)));
                        goto Label_0189;

                    case "Byte":
                        d = (int) Math.Ceiling(d);
                        index = (int) d;
                        buffer[index] = (byte) info.GetValue(structValue);
                        d++;
                        goto Label_0236;

                    case "Int16":
                        buffer2 = Int.ToByteArray((short) info.GetValue(structValue));
                        goto Label_0236;

                    case "UInt16":
                        buffer2 = Word.ToByteArray((ushort) info.GetValue(structValue));
                        goto Label_0236;

                    case "Int32":
                        buffer2 = DInt.ToByteArray((int) info.GetValue(structValue));
                        goto Label_0236;

                    case "UInt32":
                        buffer2 = DWord.ToByteArray((uint) info.GetValue(structValue));
                        goto Label_0236;

                    case "Double":
                        buffer2 = S7.Net.Types.Double.ToByteArray((double) info.GetValue(structValue));
                        goto Label_0236;

                    default:
                        goto Label_0236;
                }
                buffer[index] = (byte) (buffer[index] & ~((byte) Math.Pow(2.0, (double) num3)));
            Label_0189:
                d += 0.125;
            Label_0236:
                if (buffer2 != null)
                {
                    d = Math.Ceiling(d);
                    if (((d / 2.0) - Math.Floor((double) (d / 2.0))) > 0.0)
                    {
                        d++;
                    }
                    index = (int) d;
                    for (int i = 0; i < buffer2.Length; i++)
                    {
                        buffer[index + i] = buffer2[i];
                    }
                    d += buffer2.Length;
                }
            }
            return buffer;
        }
    }
}

